// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//

#ifndef __GCU_H__
#define __GCU_H__

#include <windows.h>
#include <csync.h>
#include <cmthread.h>
#include "gcu_common.h"
#include "clkmgr.h"

/*****************************************************************************
 * Register defines
 */

/* 
 * Graphics Controller Configuration Register (GCCR)
 */

#define GCCR_BP_RST        (1U<<8) /* Breatpoint Reset */
#define GCCR_ABORT        (1U<<6)    /* Abort all current activity in te 2D Graphics Engine */
#define GCCR_STOP        (1U<<4)    /* Halt the 2D Graphics Engine */

#define GCCR_MASK        (0x0000075F)

/* 
 * Graphics Controller Interrupt Status Controller Register(GCISR) 
 */
const UINT32 GCISCR_MASK = 0x000001ff;
#define GCISCR_FLAG_INTST    (1U<<8) /* Graphics Controller GCFLAGS Register Interrupt status */
#define GCISCR_STOP_INTST    (1U<<7) /* Graphics Controller GCCR:Stop Response interrupt status */
#define GCISCR_PF_INST        (1U<<6) /* Graphics Controller Illegal/Incompatible Pixel Format, Step Size interrupt Status */
#define GCISCR_EEOB_INTST    (1U<<5)    /* Graphics Controller Execution End of Buffer interrupt stauts */
#define GCISCR_IIN_INTST    (1U<<4)    /* Graphics Controller Illegal Instruction Interrupt Status */
#define GCISCR_IOP_INTST    (1U<<3)    /* Graphics Controller Illegal Operation Interrupt Status */
#define GCISCR_BF_INTST        (1U<<2)    /* Graphics Controller Display Buffer Flip Interrupt Status */
#define GCISCR_IN_INTST        (1U<<1)    /* Graphics Controller Instruction Interrup Status */
#define GCISCR_EOB_INTST    (1U<<0)    /* Graphics COntroller End of Buffer (Ring buffer HEAD = Ring Buffer TAIL) Interrupt Status */

/*
 * Graphics Controller Interrupt Enable Control Register (GCIECR) 
 */

const UINT32 GCIECR_MASK = 0x000001ff;

#define GCIECR_FLAG_INTEN    (1U<<8) /* Graphics Controller GCFLAGS Register Interrupt Enable */
#define GCIECR_STOP_INTEN    (1U<<7) /* Graphics Controller GCCR:Stop Response interrupt Enable */
#define GCIECR_PF_INTEN        (1U<<6) /* Graphics Controller Illegal/Incompatible Pixel Format, Step Size interrupt Enable */
#define GCIECR_EEOB_INTEN    (1U<<5)    /* Graphics Controller Execution End of Buffer Interrupt Enable */
#define GCIECR_IIN_INTEN    (1U<<4)    /* Graphics Controller Illegal Instruction Interrupt Enable */
#define GCIECR_IOP_INTEN    (1U<<3)    /* Graphics Controller Illegal Operation Interrupt Eanble */
#define GCIECR_BF_INTEN        (1U<<2)    /* Graphics Controller Display Buffer Flip Interrupt Enable */
#define GCIECR_IN_INTEN        (1U<<1)    /* Graphics Controller Instruction Interrup Enable */
#define GCISCR_EOB_INTEN    (1U<<0)    /* Graphics COntroller End of Buffer (Ring buffer HEAD = Ring Buffer TAIL) Interrupt Status */

/*
 * Graphics Controller ALU Flags Register (GCFLAGS)
 */

#define GCFLAGS_ZERO_R        (1U<<12) /* A calculated Red value was under flowed and has been clipped to 0x0000 */
#define GCFLAGS_SAT_G        (1U<<9)     /* A calculated Green value was saturated and has been clipped to 0xFFFF */
#define GCFLAGS_ZOAR_G        (1U<<8)     /* A calculated Green value was under flowed and has been clipped to 0x0000 */
#define GCFLAGS_SAT_B        (1U<<5)     /* A calculated Blue value was saturated and has been clipped to 0xFFFF */
#define GCFLAGS_ZOAR_B        (1U<<4)     /* A calculated Blue value was under flowed and has been clipped to 0x0000 */
#define GCFLAGS_SAT_A        (1U<<1)     /* A calculated Alpha value was saturated and has been clipped to 0xFFFF */
#define GCFLAGS_ZOAR_A        (1U<<0)     /* A calculated Alpha value was under flowed and has been clipped to 0x0000 */

struct GCURegs
{
    /* Miscellaneous Control and Interrupt Information */
    UINT32 gccr;       /* Configuration Register */
    UINT32 gciscr;     /* Interrupt Status Control Register */
    UINT32 gciecr;     /* Interrupt Enable Control Register */
    UINT32 gcnopid;    /* NOP ID From Instruction Stream Register */
    UINT32 gcalphaset; /* Default Alpha value Control Register */
    UINT32 gctset;     /* Default Transparecy Value Control Register */
    UINT32 gcflags;    /* ALU Ooperations Flags Status Control Register */

    /* Reserved 0x5400001C */
    UINT32 res0[1];

    /* Ring Buffer Information */
    UINT32 gcrbbr;    /* Ring Buffer Base Address Register */
    UINT32 gcrblr;    /* Ring Buffer Length Register */
    UINT32 gcrbhr;    /* Ring Buffer Head Register */
    UINT32 gcrbtr;    /* Ring Buffer Tail Register */
    UINT32 gcrbexhr;  /* Ring Buffer Execution Head Register */

    /* Reserved 0x54000034-0x5400003C */
    UINT32 res1[3];
    
    /* Batch Buffer Information */
    UINT32 gcbbbr;    /* Batch Buffer Base Address Register */
    UINT32 gcbbhr;    /* Batch Buffer Head Register */
    UINT32 gcbbexhr;  /* Batch Buffer Execution Head Register */

    /* Reserved 0x5400004C - 0x5400005C */
    UINT32 res2[5];

    /* Destination 0 Information */
    UINT32 gcd0br;     /* Destination 0 Base Address Register */
    UINT32 gcd0stp;    /* Destination 0 Step Size Register */
    UINT32 gcd0str;    /* Destination 0 Stride Size Register */
    UINT32 gcd0pf;     /* Destination 0 Pixel Type Register */

    /* Destination 1 Information */
    UINT32 gcd1br;     /* Destination 1 Base Address Register */
    UINT32 gcd1stp;    /* Destination 1 Step Size Register */
    UINT32 gcd1str;    /* Destination 1 Stride Size Register */
    UINT32 gcd1pf;     /* Destination 1 Pixel Type Register */
    
    /* Destination 2 Information */
    UINT32 gcd2br;   /* Destination 2 Base Address Register */
    UINT32 gcd2stp;  /* Destination 2 Step Size Register */
    UINT32 gcd2str;  /* Destination 2 Stride Size Register */
    UINT32 gcd2pf;   /* Destination 2 Pixel Type Register */
    
    /* Reserved 0x54000090-0x540000DC */
    UINT32 res3[20];

    /* Source 0 Information */
    UINT32 gcs0br;     /* Source 0 Base Address Register */
    UINT32 gcs0stp;    /* Source 0 Step Size Register */
    UINT32 gcs0str;    /* Source 0 Stride Size Register */
    UINT32 gcs0pf;     /* Source 0 Pixel Type Register */

    /* Source 1 Information */
    UINT32 gcs1br;     /* Source 1 Base Address Register */
    UINT32 gcs1stp;    /* Source 1 Step Size Register */
    UINT32 gcs1str;    /* Source 1 Stride Size Register */
    UINT32 gcs1pf;     /* Source 1 Pixel Type Register */

    /* Resvered 0x54000100-0x5400015C */
    UINT32 res4[24];

    /* Pixel ALU Scratch Registers */
    UINT32 gcsc0wd0; /* Pixel ALU Scratch Register 0 Word 0 */
    UINT32 gcsc0wd1; /* Pixel ALU Scratch Register 0 Word 1 */
    UINT32 gcsc1wd0; /* Pixel ALU Scratch Register 1 Word 0 */
    UINT32 gcsc1wd1; /* Pixel ALU Scratch Register 1 Word 1 */
    UINT32 gcsc2wd0; /* Pixel ALU Scratch Register 2 Word 0 */
    UINT32 gcsc2wd1; /* Pixel ALU Scratch Register 2 Word 1 */
    UINT32 gcsc3wd0; /* Pixel ALU Scratch Register 3 Word 0 */
    UINT32 gcsc3wd1; /* Pixel ALU Scratch Register 3 Word 1 */
    UINT32 gcsc4wd0; /* Pixel ALU Scratch Register 4 Word 0 */
    UINT32 gcsc4wd1; /* Pixel ALU Scratch Register 5 Word 1 */
    UINT32 gcsc5wd0; /* Pixel ALU Scratch Register 5 Word 0 */
    UINT32 gcsc5wd1; /* Pixel ALU Scratch Register 5 Word 1 */
    UINT32 gcsc6wd0; /* Pixel ALU Scratch Register 6 Word 0 */
    UINT32 gcsc6wd1; /* Pixel ALU Scratch Register 6 Word 1 */
    UINT32 gcsc7wd0; /* Pixel ALU Scratch Register 7 Word 0 */
    UINT32 gcsc7wd1; /* Pixel ALU Scratch Register 7 Word 1 */

    /* Reserved 0x540001A0~0x540001DC */
    UINT32 res5[16];

    /* Abort Bad Address Storage Registers */
    UINT32 gccabaddr;
    UINT32 gctabaddr;
    UINT32 gcmabaddr;
};

class GCUIntrThread : public CMiniThread
{
public:
    GCUIntrThread();
private:
    DWORD ThreadRun();
    bool init();
    const UINT32 irq;
    UINT32 sys_intr;
    HANDLE intr_event;
};

class GCUProxy;
class IPMClient;

class GCU
{
public:
    GCU(IPMClient* ipm);
    bool init();
    void sync();
    void reset();

    void suspend();
    void resume();
    void handle_intr();
    static GCU* get_gcu();

    bool handle_client(GCUProxy* proxy, UINT32* cmd_buf, UINT cmd_size);
    void invalidate_context(GCUProxy* invalid_context);     

private:
    static const UINT ring_buf_size = 0x5000;
    void _reset();
    bool submit(UINT32* buf, UINT32 size);
    void set_power_mode(bool is_on);
    void request_clock(bool is_required);
    bool init_memory();
    void init_power();

    HANDLE idle_event;
    volatile GCURegs* regs;
    
    /* Ring Buffer */
    struct
    {
        UINT32* buf;
        UINT32 size;
        UINT32 base;
    } ring_buf;

    IPMClient* ipm_client;

    GCUProxy* context;
    GCUIntrThread intr_thread;
    CLockObject lock;
    static GCU* gcu;
    bool clock_state;
    bool need_reset;
    CLKMGR clk_mgr;
};

class GCUProxy
{
public:
    ~GCUProxy();
    void sync();
    bool submit(UINT32* new_context, UINT new_context_size,
                UINT32* cmd_buf, UINT cmd_size);
    UINT32* get_context_cmd_buf();
    UINT get_context_cmd_size();
private:
    UINT32 context_buf[context_cmd_size];
    UINT context_size;
    static CLockObject context_lock;
};

#endif // __GCU_H__
